<template>
  <view class="drawer-container" v-if="show || isTransitioning">
    <!-- 遮罩层 - 带淡入淡出动画 -->
    <view
      class="drawer-mask"
      :class="{ 'mask-visible': show }"
      @click="handleMaskClick"
      :style="{
        backgroundColor: maskColor,
        transition: `opacity ${props.duration}ms ${
          show ? props.openTimingFunction : props.closeTimingFunction
        }`,
      }"
      v-if="mask"
    ></view>

    <!-- 抽屉内容 - 带滑入滑出动画 -->
    <view
      class="drawer-content"
      :class="[direction]"
      :style="[contentStyle]"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @transitionend="handleTransitionEnd"
    >
      <!-- 插槽：抽屉头部 -->
      <slot name="header"></slot>

      <!-- 插槽：抽屉主体内容 -->
      <slot></slot>

      <!-- 插槽：抽屉底部 -->
      <slot name="footer"></slot>
    </view>
  </view>
</template>

<script setup>
import { ref, computed, watch, nextTick } from 'vue';

// 定义组件属性
const props = defineProps({
  // 是否显示抽屉
  show: {
    type: Boolean,
    default: false,
  },
  // 抽屉方向：left/right/top/bottom
  direction: {
    type: String,
    default: 'right',
    validator: (value) => {
      return ['left', 'right', 'top', 'bottom'].includes(value);
    },
  },
  // 抽屉宽度/高度，根据方向自动应用
  size: {
    type: [String, Number],
    default: 300,
  },
  // 是否显示遮罩
  mask: {
    type: Boolean,
    default: true,
  },
  // 点击遮罩是否关闭抽屉
  maskClosable: {
    type: Boolean,
    default: true,
  },
  // 遮罩背景色
  maskColor: {
    type: String,
    default: 'rgba(0, 0, 0, 0.5)',
  },
  // 遮罩透明度
  maskOpacity: {
    type: Number,
    default: 0.5,
  },
  // 是否支持滑动关闭
  swipeClosable: {
    type: Boolean,
    default: true,
  },
  // 动画持续时间(ms)
  duration: {
    type: Number,
    default: 300,
  },
  // 开启动画曲线
  openTimingFunction: {
    type: String,
    default: 'cubic-bezier(0.4, 0, 0.2, 1)', // 缓入缓出
  },
  // 关闭动画曲线
  closeTimingFunction: {
    type: String,
    default: 'cubic-bezier(0.4, 0, 0.6, 1)',
  },
});

// 定义事件
const emitEvent = defineEmits(['close', 'animation-end']);

// 状态管理
const startPos = ref(0);
const moveDistance = ref(0);
const isDragging = ref(false);
const isTransitioning = ref(false); // 控制动画期间组件不被销毁
const isVisible = ref(props.show); // 用于触发动画的内部状态

// 计算抽屉内容样式
const contentStyle = computed(() => {
  const size = typeof props.size === 'number' ? `${props.size}px` : props.size;
  const timingFunction = isVisible.value
    ? props.openTimingFunction
    : props.closeTimingFunction;

  const style = {
    width:
      props.direction === 'left' || props.direction === 'right' ? size : '100%',
    height:
      props.direction === 'top' || props.direction === 'bottom' ? size : '100%',
    transition: isDragging.value
      ? 'none'
      : `transform ${props.duration}ms ${timingFunction}`,
    zIndex: 9999,
    willChange: 'transform',
  };

  // 基础位置（关闭状态）
  let baseTransform;
  switch (props.direction) {
    case 'left':
      baseTransform = 'translateX(-100%)';
      break;
    case 'right':
      baseTransform = 'translateX(100%)';
      break;
    case 'top':
      baseTransform = 'translateY(-100%)';
      break;
    case 'bottom':
      baseTransform = 'translateY(100%)';
      break;
  }

  // 应用滑动或显示状态
  if (isDragging.value && props.swipeClosable) {
    if (props.direction === 'left' || props.direction === 'right') {
      const sign = props.direction === 'right' ? 1 : -1;
      style.transform = `translateX(${sign * moveDistance.value}px)`;
    } else {
      const sign = props.direction === 'bottom' ? 1 : -1;
      style.transform = `translateY(${sign * moveDistance.value}px)`;
    }
  } else {
    style.transform = isVisible.value ? 'translate(0, 0)' : baseTransform;
  }

  return style;
});

// 监听show变化，触发动画
watch(
  () => props.show,
  async (newVal) => {
    if (newVal) {
      // 打开抽屉：先确保组件已渲染，再触发动画
      isTransitioning.value = true;
      await nextTick(); // 等待DOM更新
      isVisible.value = true;
    } else {
      // 关闭抽屉：先触发动画，完成后隐藏
      isVisible.value = false;
      isTransitioning.value = true;
    }
  },
);

// 处理动画结束
const handleTransitionEnd = () => {
  if (!isVisible.value) {
    isTransitioning.value = false;
  }
  emitEvent('animation-end', isVisible.value);
};

// 关闭抽屉
const closeDrawer = () => {
  emitEvent('close');
};

// 点击遮罩关闭
const handleMaskClick = () => {
  if (props.mask && props.maskClosable) {
    closeDrawer();
  }
};

// 触摸开始
const handleTouchStart = (e) => {
  if (!props.swipeClosable) return;

  isDragging.value = true;
  if (props.direction === 'left' || props.direction === 'right') {
    startPos.value = e.touches[0].clientX;
  } else {
    startPos.value = e.touches[0].clientY;
  }
};

// 触摸移动
const handleTouchMove = (e) => {
  if (!props.swipeClosable || !isDragging.value) return;

  let currentPos;
  if (props.direction === 'left' || props.direction === 'right') {
    currentPos = e.touches[0].clientX;
    if (props.direction === 'right') {
      moveDistance.value = Math.min(0, currentPos - startPos.value);
    } else {
      moveDistance.value = Math.max(0, startPos.value - currentPos);
    }
  } else {
    currentPos = e.touches[0].clientY;
    if (props.direction === 'bottom') {
      moveDistance.value = Math.min(0, currentPos - startPos.value);
    } else {
      moveDistance.value = Math.max(0, startPos.value - currentPos);
    }
  }
};

// 触摸结束
const handleTouchEnd = () => {
  if (!props.swipeClosable || !isDragging.value) return;

  isDragging.value = false;
  const size =
    typeof props.size === 'number' ? props.size : parseInt(props.size);

  if (Math.abs(moveDistance.value) > size / 3) {
    closeDrawer();
  } else {
    // 回弹动画
    moveDistance.value = 0;
  }
};
</script>

<style scoped>
.drawer-container {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  z-index: 9998;
}

.drawer-mask {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  opacity: 0;
  pointer-events: none;
}

.mask-visible {
  opacity: v-bind(maskOpacity);
  pointer-events: auto;
}

.drawer-content {
  position: absolute;
  background-color: #fff;
  box-shadow: 0 0 15px rgba(0, 0, 0, 0.15);
  pointer-events: auto;
}

/* 方向定位 */
.left {
  top: 0;
  left: 0;
}

.right {
  top: 0;
  right: 0;
}

.top {
  top: 0;
  left: 0;
}

.bottom {
  left: 0;
  bottom: 0;
}
</style>
